#include "clientrunable.h"

clientRunable::clientRunable(qintptr sock, QObject *parent) : QObject(parent),p(new clientRunablePrivate)
{
    p->sock = sock;
    setAutoDelete(true);
}

void clientRunable::run()
{
    QTcpSocket socket;
    socket.setSocketDescriptor(p->sock);   /* 把通信套接字给到通信类 */

    if(!socket.waitForConnected(3000))      /* 等待连接，时长3s */
    {
        return;                         /* 当前套接字失效，不能实现tcp连接 */
    }
    QHostAddress address = socket.peerAddress();

    QEventLoop loop; // QT 事件循环

    // 当放出信号的对象释放，connect 自动断开连接
    // readyRead : tcp 缓冲区中有数据可以读取
    // 发一包数据触发一次（不是）  而是   tcp缓冲区满(65535->64k数据) 或 发送结束才触发信号
    // 包头: 用来截断数据包，防止发生粘包的问题
    connect(&socket,&QTcpSocket::readyRead,[this,&socket]()
    {
        auto Content = socket.readAll();                                    // 读出缓冲区中所有的数据

        buffer.append(Content);                                             // 放入我们自己的缓冲区
        while(buffer.size() > sizeof(size_t))                      // 缓冲区的数据大于包头(确保可以读取) 使用 uint64_t 会比使用 uint32_t 消耗更多的内存和网络带宽
        {
            size_t size = 0;
            memcpy(&size,buffer.data(),sizeof(size_t));            // 提取包头

            if(buffer.size() < size + sizeof (size_t))              // 缓冲区数据量不足以解析一个json包(包头和包体)
            {
                break;                                                      // 等待下一个缓冲区里的数据
            }
            auto data = buffer.mid(sizeof(size_t),size);            // 从缓冲区提取包体的数据(跳过包头的部分)
            // json 解析
            QJsonDocument doc = QJsonDocument::fromJson(data);        // 尝试将提取的数据解析为Json文档
            QJsonObject jsonObj = doc.object();                        // 获取Json对象

            int type = jsonObj["type"].toInt();
            qDebug()<<"服务器解析出来的类型为 :"<<type;

            this->p->handleJsonP = GetHandlePtr(type);
            this->p->handleJsonP->Handle(jsonObj,&socket);

            buffer.remove(0, size + sizeof(size_t));                         // 从缓冲区中删除这个被解析过的数据包
        }
    });

    connect(&socket,&QTcpSocket::disconnected,[&loop,&socket]()
    {
        loop.exit();                                                        // 断开了连接 退出事件循环
        qDebug()<<"客户端已退出"<<socket.peerAddress()<<endl;
    });
    loop.exec();                // 执行事件循环：死循环监听信号和槽

    // 收尾
    socket.close();               // 关闭套接字
}
